#include "CppUTest/TestHarness.h"

extern "C"
{
#include "can/can_mail.h"
#include "platform_errno.h"
}

static struct CanRxBox *g_rbox;
static struct CanMsgPool *g_pool;

TEST_GROUP(can_mail_test)
{
    void setup()
    {
        g_rbox = CanRxBoxCreate();
        CHECK_FALSE(g_rbox == NULL);
        g_pool = CanMsgPoolCreate(8); // 8, pool size
        CHECK_FALSE(g_pool == NULL);
    }

    void teardown()
    {
        CanRxBoxDestroy(g_rbox);
        CanMsgPoolDestroy(g_pool);
    }
};

static bool CanRxBoxCanGetMsg(struct CanRxBox *rbox, struct CanMsg *msg)
{
    struct CanMsg *msgGot = NULL;

    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxGetMsg(g_rbox, &msgGot, 0));
    CHECK_TRUE(msg == msgGot);
    CanMsgPut(msgGot);
    return true;
}

static bool CanRxBoxCanNotGetMsg(struct CanRxBox *rbox, struct CanMsg *msg)
{
    struct CanMsg *msgGot = NULL;

    LONGS_EQUAL(HDF_PLT_ERR_NO_DATA, CanRxBoxGetMsg(g_rbox, &msgGot, 0));
    CHECK_TRUE(NULL == msgGot);
    return true;
}

static bool CanRxBoxCanAddAndGetMsg(struct CanRxBox *rbox, struct CanMsg *msg)
{
    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddMsg(g_rbox, msg));
    return CanRxBoxCanGetMsg(rbox, msg);
}

TEST(can_mail_test, should_lock_and_unlock_rx_box)
{
    CanRxBoxLock(g_rbox);
    CanRxBoxUnlock(g_rbox);
}

TEST(can_mail_test, should_add_and_get_msg)
{
    //struct CanMsg *msg = CanMsgObtain();
    struct CanMsg *msg = CanMsgPoolObtainMsg(g_pool);
    CHECK_TRUE(CanRxBoxCanAddAndGetMsg(g_rbox, msg));
    CanMsgPut(msg);
}

#define CAN_TEST_ID_A 0x15A
#define CAN_TEST_ID_B 0x2A5
#define CAN_TEST_ID_C 0x555
#define CAN_MASK_FULL 0x1FFFFFFF
#define CAN_TEST_DATA 0xAB

static struct CanFilter g_filterA = {
    .rtr = 0,
    .ide = 0,
    .id = CAN_TEST_ID_A,
    .rtrMask = 1,
    .ideMask = 1,
    .idMask = CAN_MASK_FULL,
};

static struct CanFilter g_filterB = {
    .rtr = 0,
    .ide = 0,
    .id = CAN_TEST_ID_B,
    .rtrMask = 1,
    .ideMask = 1,
    .idMask = CAN_MASK_FULL,
};

static struct CanMsg *CanMsgObtainByParms(uint32_t id, uint32_t ide, uint32_t rtr, uint8_t data)
{
    int i;
    //struct CanMsg *msg = CanMsgObtain();
    struct CanMsg *msg = CanMsgPoolObtainMsg(g_pool);

    if (msg == NULL) {
        return msg;
    }
    msg->ide = ide;
    msg->id = id;
    msg->rtr = rtr;
    for (i = 0; i < (uint8_t)(sizeof(msg->data)); i++) {
        msg->data[i] = data;
    }
    msg->dlc = i;
    msg->error = 0;
    return msg;
}

TEST(can_mail_test, should_add_and_del_filter)
{
    struct CanMsg *msgA = CanMsgObtainByParms(CAN_TEST_ID_A, 0, 0, CAN_TEST_DATA);
    CHECK_FALSE(msgA == NULL);
    struct CanMsg *msgB = CanMsgObtainByParms(CAN_TEST_ID_B, 0, 0, CAN_TEST_DATA);
    CHECK_FALSE(msgB == NULL);

    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddFilter(g_rbox, &g_filterA));
    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddMsg(g_rbox, msgA));
    LONGS_EQUAL(HDF_ERR_NOT_SUPPORT, CanRxBoxAddMsg(g_rbox, msgB));
    CHECK_TRUE(CanRxBoxCanGetMsg(g_rbox, msgA));
    CHECK_TRUE(CanRxBoxCanNotGetMsg(g_rbox, msgA));

    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxDelFilter(g_rbox, &g_filterA));
    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddMsg(g_rbox, msgB));
    CHECK_TRUE(CanRxBoxCanGetMsg(g_rbox, msgB));

    CanMsgPut(msgA);
    CanMsgPut(msgB);
}


TEST(can_mail_test, should_add_multi_filters)
{
    struct CanMsg *msgA = CanMsgObtainByParms(CAN_TEST_ID_A, 0, 0, CAN_TEST_DATA);
    CHECK_FALSE(msgA == NULL);
    struct CanMsg *msgB = CanMsgObtainByParms(CAN_TEST_ID_B, 0, 0, CAN_TEST_DATA);
    CHECK_FALSE(msgB == NULL);
    struct CanMsg *msgC = CanMsgObtainByParms(CAN_TEST_ID_C, 0, 0, CAN_TEST_DATA);
    CHECK_FALSE(msgC == NULL);

    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddFilter(g_rbox, &g_filterA));
    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddFilter(g_rbox, &g_filterB));

    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddMsg(g_rbox, msgA));
    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxAddMsg(g_rbox, msgB));

    CHECK_TRUE(CanRxBoxCanGetMsg(g_rbox, msgA));
    CHECK_TRUE(CanRxBoxCanGetMsg(g_rbox, msgB));

    LONGS_EQUAL(HDF_ERR_NOT_SUPPORT, CanRxBoxAddMsg(g_rbox, msgC));

    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxDelFilter(g_rbox, &g_filterA));
    LONGS_EQUAL(HDF_SUCCESS, CanRxBoxDelFilter(g_rbox, &g_filterB));

    CHECK_TRUE(CanRxBoxCanAddAndGetMsg(g_rbox, msgC));

    CanMsgPut(msgA);
    CanMsgPut(msgB);
    CanMsgPut(msgC);
}
